home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / ici / ici.cpi / alloc.c < prev    next >
C/C++ Source or Header  |  1994-10-27  |  6KB  |  266 lines

  1. #include "fwd.h"
  2. #include "trace.h"
  3. /*
  4.  * alloc.c
  5.  *
  6.  * Lowest level of ICI memory allocation before going to the host malloc()
  7.  * function. Principle functions are ici_alloc() and ici_free(). Although
  8.  * these are virtually never called directly but always through the macros
  9.  * zalloc() and zfree() defined in alloc.h.
  10.  */
  11.  
  12. #define    ALLCOLLECT    0    /* Collect on every ici_alloc call. */
  13. #define    ALLALLOC    0    /* Always call ici_alloc, no caches. */
  14.  
  15. #if    WHOALLOC
  16. #undef    ALLALLOC
  17. #define    ALLALLOC    1    /* WHOALLOC requires. */
  18. #endif
  19.  
  20. #if    ALLALLOC
  21. #undef    galist
  22. #define    galist(n)    0    /* List "0" is direct calls to ici_alloc. */
  23. #endif
  24.  
  25. char        *ici_fflist[3];    /* The array of fast free lists heads. */
  26. char        *ici_fftmp;    /* Temporary used in zalloc() (alloc.h). */
  27. long        ici_old_mem;    /* Num bytes in use after last collect. */
  28. long        ici_new_mem;    /* Num bytes alloced since last collect. */
  29.  
  30. #if    WHOALLOC
  31. /*
  32.  * WHOALLOC (see comment at top of alloc.h) works by keeping a hash table
  33.  * keyed by file name and line number. Each allocation looks up its record
  34.  * in this table and the index of that record goes in the header of the block
  35.  * allocated along with the size of the alloc. The record in the hash table
  36.  * notes the total allocations made from that location. A free pulls out
  37.  * the index of the record and subtracts the size stored in the header from
  38.  * the total in the record.
  39.  *
  40.  * Thus at any time the hash table can be scanned and all source locations
  41.  * with outstanding allocations can be printed.
  42.  */
  43. typedef struct
  44. {
  45.     char    *w_file;
  46.     int        w_line;
  47.     long    w_alloced;
  48. }
  49.     who_t;
  50.  
  51. who_t    wtab[197];    /* Prime(ish) and larger than num alloc()s in source.*/
  52.  
  53. /*
  54.  * Return a pointer to the WHOALLOC record for given file and line number.
  55.  */
  56. static who_t *
  57. find_who_slot(char *file, int line)
  58. {
  59.     who_t        *w;
  60.     unsigned long    h;
  61.     unsigned char    *p;
  62.  
  63.     h = line;
  64.     for (p = (unsigned char *)file; *p != NULL; ++p)
  65.     h = (h << 3) ^ (h >> 24) ^ *p;
  66.     for
  67.     (
  68.     w = &wtab[h % nels(wtab)];
  69.     w->w_file != NULL && (w->w_line != line || strcmp(w->w_file,file) != 0);
  70.     --w
  71.     )
  72.     {
  73.     if (w == wtab)
  74.         w = &wtab[nels(wtab)];
  75.     }
  76.     return w;
  77. }
  78.  
  79. /*
  80.  * Record this allocation against the given file and line number.
  81.  */
  82. static void
  83. note_who_alloced(void *p, int size, char *file, int line)
  84. {
  85.     who_t    *w;
  86.  
  87.     w = find_who_slot(file, line);
  88.     if (w->w_file == NULL)
  89.     {
  90.     w->w_file = file;
  91.     w->w_line = line;
  92.     }
  93.     w->w_alloced += size;
  94.     gahead(p)->ga_who = w - wtab;
  95.     gahead(p)->ga_size = size;
  96. }
  97.  
  98. /*
  99.  * Reverse the record of allocation of this block.
  100.  */
  101. static void
  102. note_free(void *p)
  103. {
  104.     wtab[gahead(p)->ga_who].w_alloced -= gahead(p)->ga_size;
  105. }
  106.  
  107. /*
  108.  * Print a table of outstanding allocation amounts by file and line number.
  109.  */
  110. static void
  111. report_who_still_alloced(void)
  112. {
  113.     who_t    *w;
  114.  
  115.     for (w = wtab; w < &wtab[nels(wtab)]; ++w)
  116.     {
  117.     if (w->w_alloced == 0)
  118.         continue;
  119.     fprintf(stderr, "%7d bytes from %s %d\n",
  120.         w->w_alloced,
  121.         w->w_file,
  122.         w->w_line);
  123.     }
  124. }
  125. #endif /*WHOALLOC*/
  126.  
  127. /*
  128.  * Free everything on our fast free lists. Done just before a regular
  129.  * garbage collection because things still on them were not used and
  130.  * this is a good predictor that they won't be used again.
  131.  *
  132.  * Done after an externally prompted collection so that as much memory
  133.  * as possible is released.
  134.  */
  135. static void
  136. drop_fast_free_lists(void)
  137. {
  138.     char    *p;
  139.     int        i;
  140.  
  141.     for (i = 0; i < nels(ici_fflist); ++i)
  142.     {
  143.     while (ici_fflist[i] != NULL)
  144.     {
  145.         p = ici_fflist[i];
  146.         ici_fflist[i] = *(char **)p;
  147.         ici_free(p);
  148.     }
  149.     }
  150. }
  151.  
  152. /*
  153.  * Normal collection. Triggered by having allocated as much new memory
  154.  * as we previsouly has memory tied up in objects after the previous
  155.  * garbage collect.
  156.  */
  157. static void
  158. normal_reclaim(void)
  159. {
  160.     /*
  161.      * We've allocated as much new memory as we had things to
  162.      * start with.  Time to garbage collect.  First we throw away
  163.      * our private lists (because we hardly ever free things outside
  164.      * garbage collection, the things on them now obviously have been
  165.      * there since the last garbage collection and they weren't needed,
  166.      * so toss 'em).
  167.      */
  168.     drop_fast_free_lists();
  169.     collect();
  170. }
  171.  
  172. /*
  173.  * Garbage collection triggered by other than our internal mechanmism.
  174.  * Don't do this unless you really must. It will free all memory it can
  175.  * but will reduce subsequent performance.
  176.  */
  177. void
  178. ici_reclaim(void)
  179. {
  180.     collect();
  181.     drop_fast_free_lists();
  182. #if    WHOALLOC
  183.     report_who_still_alloced();
  184. #endif
  185. }
  186.  
  187. void *
  188. #if    WHOALLOC
  189. ici_alloc(int n, char *file, int line)
  190. #else
  191. ici_alloc(int n)
  192. #endif
  193. {
  194.     char    *p;
  195.  
  196. #ifndef NOTRACE
  197.     if (trace_yes && (trace_flags & TRACE_MEM))
  198.         fprintf(stderr, "trace: ici_alloc %d bytes\n", n);
  199. #endif
  200.  
  201. #if    !ALLCOLLECT
  202.     if ((ici_new_mem += n) > ici_old_mem)
  203. #endif
  204.     normal_reclaim();
  205.  
  206.     switch (galist(n))
  207.     {
  208.     case 1:
  209.     if (ici_fflist[1] != NULL)
  210.     {
  211.         ici_fflist[1] = *(char **)(p = ici_fflist[1]);
  212.         return p;
  213.     }
  214.     n = LIST1Z;
  215.     break;
  216.  
  217.     case 2:
  218.     if (ici_fflist[2] != NULL)
  219.     {
  220.         ici_fflist[2] = *(char **)(p = ici_fflist[2]);
  221.         return p;
  222.     }
  223.     n = LIST2Z;
  224.     break;
  225.     }
  226.  
  227.     n += GALLOC_HEADZ;
  228.     if
  229.     (
  230.     (p = malloc((unsigned)n)) == NULL
  231.     &&
  232.     (
  233.         ici_new_mem == 0
  234.         ||
  235.         (normal_reclaim(), (p = malloc((unsigned)n)) == NULL)
  236.     )
  237.     )
  238.     {
  239.     error = "ran out of memory";
  240.     return NULL;
  241.     }
  242.  
  243. #ifdef    BUGHUNT
  244.     memset(p, rand(), n);
  245. #endif
  246.  
  247. #ifndef    SMALL
  248.     ((gahead_t *)p)->ga_list = galist(n - GALLOC_HEADZ);
  249. #endif
  250.  
  251. #if    WHOALLOC
  252.     note_who_alloced(gadata(p), n, file, line);
  253. #endif
  254.  
  255.     return gadata(p);
  256. }
  257.  
  258. void
  259. ici_free(void *p)
  260. {
  261. #if    WHOALLOC
  262.     note_free(p);
  263. #endif
  264.     free((void *)gahead(p));
  265. }
  266.